package us.wili.dev.common.util;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;

/**
 * Created by JasonY on 17/2/18.
 */
public class HttpServletRequestUtil {

    private static final String EXPIRE_SECONDS_SUFFIX = "_expireSeconds";
    private static final String REFRESH_EXPIRATION_SUFFIX = "_refreshExpiration";
    private static final String EXPIRATION_TIME_SUFFIX = "_expirationTime";

    public static boolean isAjax(HttpServletRequest request) {
        return "XMLHttpRequest".equalsIgnoreCase( request.getHeader("X-Requested-With") );
    }

    public static boolean wantsJson(HttpServletRequest request) {
        String acceptHeader = request.getHeader("Accept");
        boolean acceptJson = (acceptHeader != null && acceptHeader.indexOf("application/json") > -1);
        boolean needJsonContentType = ("application/json".equalsIgnoreCase(request.getContentType()));

        return acceptJson || needJsonContentType;
    }

    public static void setAttribute(HttpServletRequest request, String name, Object value) {
        request.getSession().setAttribute(name, value);
    }

    public static void setAttribute(HttpServletRequest request, String name, Object value, long expireSeconds, boolean refreshAccessTime) {
        request.getSession().setAttribute(name, value);
        request.getSession().setAttribute(name + EXPIRE_SECONDS_SUFFIX, expireSeconds);
        request.getSession().setAttribute(name + EXPIRATION_TIME_SUFFIX, System.currentTimeMillis() + expireSeconds * 1000);
        request.getSession().setAttribute(name + REFRESH_EXPIRATION_SUFFIX, refreshAccessTime);
    }

    public static void setAttribute(HttpServletRequest request, String name, Object value, long expireSeconds) {
        setAttribute(request, name, value, expireSeconds, true);
    }

    public static Object getAttribute(HttpServletRequest request, String name) {
        Object value = request.getSession().getAttribute(name);
        Object expireSeconds = request.getSession().getAttribute(name + EXPIRE_SECONDS_SUFFIX);
        Object expirationTime = request.getSession().getAttribute(name + EXPIRATION_TIME_SUFFIX);
        Object refreshAccessTime = request.getSession().getAttribute(name + REFRESH_EXPIRATION_SUFFIX);

        // session中不存在该键值对
        if (value == null) {
            clearAttribute(request, name);
            return null;
        }

        // session中该键值对没有设置超时
        if (expireSeconds == null || !(expireSeconds instanceof Long) || expirationTime == null || !(expirationTime instanceof Long)) {
            return value;
        }

        boolean isTimeout = ((Long) expirationTime) < System.currentTimeMillis();
        // session中该键值对的生命周期已超时
        if (isTimeout) {
            clearAttribute(request, name);
            return null;
        }

        boolean willRefresh = refreshAccessTime == null || !(refreshAccessTime instanceof Boolean) ? false : (boolean) refreshAccessTime;
        if (willRefresh) {
            request.getSession().setAttribute(name + EXPIRATION_TIME_SUFFIX, System.currentTimeMillis() + ((Long) expireSeconds) * 1000);
        }

        return value;
    }

    protected static void clearAttribute(HttpServletRequest request, String name) {
        request.getSession().removeAttribute(name);
        request.getSession().removeAttribute(name + EXPIRE_SECONDS_SUFFIX);
        request.getSession().removeAttribute(name + REFRESH_EXPIRATION_SUFFIX);
    }

    private static StringBuffer getBaseUrlBuffer(HttpServletRequest request){
        StringBuffer buffer = new StringBuffer();

        buffer.append(request.getScheme()).append("://")
                .append(request.getServerName()).append(":").append(request.getServerPort());
        if (!request.getContextPath().equals("")) {
            buffer.append("/").append(request.getContextPath());
        }

        return buffer;
    }

    public static String getBaseUrl(HttpServletRequest request) {
        return getBaseUrlBuffer(request).toString();
    }

    public static String formatQueryString(Map<String, String> parameters, Boolean ifUrlEncoding) throws UnsupportedEncodingException {
        StringBuffer queryStringBuffer = new StringBuffer();
        for (String key : parameters.keySet()) {
            String value = parameters.get(key);
            if (value != null) {
                value = ifUrlEncoding ? URLEncoder.encode(value, "UTF-8") : value;
            }

            queryStringBuffer.append(key).append("=").append(value).append("&");
        }

        return queryStringBuffer.toString().replaceAll("&$", "");
    }

    public static String formatQueryString(Map<String, String> parameters) throws UnsupportedEncodingException {
        return formatQueryString(parameters, true);
    }

    public static String getFullUrl(HttpServletRequest request, String path) {
        return getBaseUrlBuffer(request).append(path).toString();
    }

    public static String getFullUrl(HttpServletRequest request, String path, Map<String, String> parameters, Boolean ifUrlEncoding) throws UnsupportedEncodingException {
        String queryString = formatQueryString(parameters, ifUrlEncoding);
        StringBuffer urlBuffer = getBaseUrlBuffer(request).append(path).append("?").append(queryString);

        return urlBuffer.toString();
    }

    public static String getFullUrl(HttpServletRequest request, String path, Map<String, String> parameters) throws UnsupportedEncodingException {
        return getFullUrl(request, path, parameters, true);
    }
}
